#region Imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Collections;

using BO = PHSRAG.Insight21.BusinessObjects;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using Utility = PHSRAG.Utility;
using PHSRAG.Insight21.CDS;
#endregion

namespace PHSRAG.Insight21.Humans
{
    #region class ProtocolDocument
    /// <summary>
    /// ProtocolDocument abstracts the notion of an attachment. 
    /// If the attachment mode is electronic, then a Document object 
    /// tied to the ProtocolDocument is used to hold the electronic file. 
    /// </summary>
    public class ProtocolDocument : BO.SmartBusinessObject, ICloneable
    {
        /// <summary>
        /// Columns of ProtocolDocument Table
        /// </summary>
        public enum ProtocolDocumentDatabaseTableColumns
        {
            Id,
            Name,
            Type,
            Required,
            HardCopy,
            DateReceived,
            DocumentId,
            ProtocolId,
            AddedPPId,
            RemovedPPId,
            IsCurrent,
            Version,
            LastLockedVersion,
            FormsId,
            Published
        }

        #region Constants
        private const string ProtocolDocumentKey = "ProtocolDocument_DDBC8686-90DF-414d-A5C1-F46414ADF430";
        private const string ProtocolDocumentDatebaseTableName = "ProtocolDocument";

        private const string ColumnNameId = "Id";
        private const string ColumnNameProtocolId = "ProtocolId";
        private const string ColumnNameName = "Name";
        private const string ColumnNameAddedPPId = "AddedPPId";
        private const string ColumnNameType = "Type";
        private const string ColumnNameRefMeaning = "RefMeaning";
        private const string ColumnNameRequired = "Required";
        private const string ColumnNameHardCopy = "HardCopy";
        private const string ColumnNameDateReceived = "DateReceived";
        private const string ColumnNameRemovedPPId = "RemovedPPId";
        private const string ColumnNameDocumentId = "DocumentId";
        private const string ColumnNameFileName = "FileName";
        private const string ColumnNameIsCurrent = "IsCurrent";
        private const string ColumnNameVersion = "Version";
        private const string COlumnNameLastLockedVersion = "LastLockedVersion";
        private const string ColumnNameReplaceable = "Replaceable";
        private const string ColumnNameFormsId = "FormsId";
        private const string ColumnNamePublished = "Published";
        private const string ColumnNameParentId = "ParentDocumentId";

        private const string GetProtocolDocumentByIdSProcName = "GetProtocolDocumentById";
        private const string SaveProtocolDocumentSProcName = "SaveProtocolDocument";
        private const string DeleteProtocolDocumentSProcName = "DeleteProtocolDocument";
        private const string GetProtocolDocumentVersionsSProcName = "GetProtocolDocumentVersions";
        private const string GetLinksToDocumentSProcName = "GetLinksToDocument";
        private const string GetProtocolDocumentsSProcName = "GetProtocolDocuments";
        private const string ValidateProtocolDocumentsProcName = "ValidateProtocolDocumentAttachment";
        #endregion

        #region Instance Variables (private)
        private int protocolId;
        private string name;
        private string type;
        private string refMeaning;
        private bool required;
        private bool hardCopy;
        private DateTime dateReceived;
        private Document electronicFile;
        private int addedPPId;
        private int removedPPId;
        private int version;
        private bool isCurrent;
        private bool markDocumentForDeletion;
        private bool markForDeletion;
        private bool includeWithSubmission;
        private bool includeEditable;
        private int lastLockedVersion;
        private bool replaceable = true;
        private string processName;
        private string processType;
        private string formsId;
        private bool published;
        private int parentDocumentId;
        #endregion


        #region Constructors
        /// <summary>
        /// Constructs a new ProtocolDocument object based on the Cache Policy passed in as a parameter. 
        /// All the instance variables will be set to their default values.
        /// </summary>
        /// <param name="cachePolicy">Cache Policy which specifies where the ProtocolDocument object should be cached</param>
        public ProtocolDocument(ICachePolicy cachePolicy)
            : base(cachePolicy){ }

        /// <summary>
        /// Constructs a new ProtocolDocument object based on the Cache Policy passed in as a parameter. 
        /// All the instance variables will be set to the corresponding values specified in the Data Row 
        /// </summary>
        /// <param name="cachePolicy">Cache Policy which specifies where the ProtocolDocument object should be cached</param>
        /// <param name="dataRow">DataRow with columns as specified in ProtocolDocumentDatabaseTableColumns</param>
        public ProtocolDocument(ICachePolicy cachePolicy, DataRow dataRow, bool gettingVersions)
            : base(cachePolicy)
        {
            PopulateMembers(dataRow, gettingVersions);
            if (dataRow[ColumnNameDocumentId] != DBNull.Value)
            {
                electronicFile.Name = (string)dataRow[ColumnNameFileName];
                electronicFile.Dirty = false;
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the ID of the Protocol to which this document belongs
        /// </summary>
        public int ProtocolId
        {
            get { return protocolId; }
            set { SetDirty(ref protocolId, value); }
        }

        /// <summary>
        /// Gets or sets the title for the Attachment
        /// </summary>
        public string Name
        {
            get { return name; }
            set { SetDirty(ref name, value); }
        }

        /// <summary>
        /// Gets or sets the Parent Document Id for the Attachment
        /// </summary>
        public int ParentDocumentId
        {
            get { return parentDocumentId; }
            set { SetDirty(ref parentDocumentId, value); }
        }

        /// <summary>
        /// Gets or sets the id of the protocol process that added the attachment
        /// </summary>
        public int AddedProtocolProcessId
        {
            get { return addedPPId; }
            set { SetDirty(ref addedPPId, value); }
        }

        /// <summary>
        /// Gets or sets the type of attachment
        /// </summary>
        public string Type
        {
            get { return type; }
            set { SetDirty(ref type, value); }
        }

        /// <summary>
        /// Gets the meaning of the protocol document type
        /// </summary>
        public string RefMeaning
        {
            get { return refMeaning; }
            set { refMeaning = value; }
        }

        /// <summary>
        /// Gets or sets whether the attachment is required(true) or optional(false)
        /// </summary>
        public bool Required
        {
            get { return required; }
            set { SetDirty(ref required, value); }
        }

        /// <summary>
        /// Gets or sets whether the attachment is Electronic(false) or HardCopy(true)
        /// </summary>
        public bool IsHardCopy
        {
            get { return hardCopy; }
            set { SetDirty(ref hardCopy, value); }
        }

        /// <summary>
        /// Gets or sets the date on which the HardCopy was received
        /// </summary>
        public DateTime DateReceived
        {
            get { return dateReceived; }
            set { SetDirty(ref dateReceived, value); }
        }

        /// <summary>
        /// Gets or sets the document id if the attachment is an electronic copy
        /// </summary>
        public Document ElectronicFile
        {
            get { return electronicFile; }
            set
            {
                //TODO: SetDirty
                electronicFile = value;
                dirty = true;
            }
        }

        /// <summary>
        /// Gets or sets the id of the protocol process that removed the attachment
        /// </summary>
        public int RemovedProtocolProcessId
        {
            get { return removedPPId; }
            set { SetDirty(ref removedPPId, value); }
        }

        /// <summary>
        /// Gets or sets whether or not the attachment is approved
        /// </summary>
        public bool IsCurrent
        {
            get { return isCurrent; }
            set { SetDirty(ref isCurrent, value); }
        }

        /// <summary>
        /// Gets or sets the version of the attachment
        /// </summary>
        public int Version
        {
            get { return version; }
            set { SetDirty(ref version, value); }
        }
        /// <summary>
        /// Gets or sets whether or not the protocol document is marked for deletion
        /// </summary>
        public bool MarkDocumentForDeletion
        {
            get { return markDocumentForDeletion; }
            set { SetDirty(ref markDocumentForDeletion, value); }
        }

        /// <summary>
        /// Marks a protocol document for deletion
        /// </summary>
        public bool MarkForDeletion
        {
            get { return markForDeletion; }
            set { SetDirty(ref markForDeletion, value); }
        }

        /// <summary>
        /// include ducument with process submission
        /// </summary>
        public bool IncludeWithSubmission
        {
            get { return includeWithSubmission; }
            set { SetDirty(ref includeWithSubmission, value); }
        }

        /// <summary>
        /// if include ducument with process submission button clickable
        /// </summary>
        public bool IncludeEditable
        {
            get { return includeEditable; }
            set { SetDirty(ref includeEditable, value); }
        }



        /// <summary>
        /// Gets or sets the last locked process version
        /// </summary>
        public int LastLockedVersion
        {
            get { return lastLockedVersion; }
            set { SetDirty(ref lastLockedVersion, value); }
        }

        /// <summary>
        /// Gets or sets whether the ProtocolDocument is replaceable or whether it should be versioned
        /// </summary>
        public bool IsReplaceable
        {
            get { return replaceable; }
        }


        /// <summary>
        /// Gets or sets the name, if any, of the process that added the staff person
        /// </summary>
        public string ProcessName
        {
            get { return processName; }
            set { processName = value; }
        }


        /// <summary>
        /// Gets or sets the type of the process that added the staff process
        /// </summary>
        public string ProcessType
        {
            get { return processType; }
            set { processType = value; }
        }


        /// <summary>
        /// Gets or sets the name of the process(ex: AME1, AME2 etc) that amended the consent form
        /// </summary>
        public string FormsId
        {
            get { return formsId; }
            set { SetDirty(ref formsId, value); }
        }


        /// <summary>
        /// Gets or sets whether or not the consent form is published
        /// </summary>
        public bool Published
        {
            get { return published; }
            set { SetDirty(ref published, value); }
        }

        #region Properties required to bind an arraylist of protocol documents to the grid
        /// <summary>
        /// Gets the Id of the contained Document object
        /// </summary>
        public int DocumentId
        {
            get
            {
                return (electronicFile != null) ? electronicFile.Id : -1;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the attachment mode is electronic
        /// </summary>
        public bool IsElectronicFile
        {
            get
            {
                return (electronicFile != null);
            }
        }

        /// <summary>
        /// Gets or Sets the name of the file if the attachment mode is electronic
        /// </summary>
        public string FileName
        {
            get
            {
                return (electronicFile != null) ? electronicFile.Name : null;
            }
            set
            {
                if (electronicFile != null)
                    electronicFile.Name = value;
            }
        }
        #endregion
        #endregion

        object ICloneable.Clone()
        {
            return Clone();
        }

        public ProtocolDocument Clone()
        {
            ProtocolDocument clone = (ProtocolDocument)MemberwiseClone();
            clone.Id = 0;
            clone.IsClone = true;
            clone.Dirty = true;
            if (ElectronicFile != null)
            {
                clone.ElectronicFile = ElectronicFile.Clone();
            }
            return clone;
        }

        #region SmartBusinessObject methods
        /// <summary>
        /// Cache Key uniquely identifies this object within the cache.
        /// </summary>
        /// <returns>the unique string for this object.</returns>
        public override string CacheKey()
        {
            return ProtocolDocumentKey;
        }


        /// <summary>
        /// Cache this instance using the prevalent cache policy.
        /// </summary>
        public override void Cache()
        {
            CachePolicy.Cache(ProtocolDocumentKey, this);
        }


        /// <summary>
        /// Remove this instance from the cache using the prevalent cache policy.
        /// </summary>
        public override void UnCache()
        {
            CachePolicy.UnCache(ProtocolDocumentKey);
        }


        /// <summary>
        /// Determines if the object is dirty based on whether or not atleast one of its properties have changed or any of its contained objects have changed
        /// </summary>
        /// <returns>true - if the object is dirty or its contained object is dirty, false - if not.</returns>
        public override bool IsDirty()
        {
            return ((ElectronicFile != null && ElectronicFile.IsDirty()) || Dirty);
        }


        /// <summary>
        /// Loads the ProtocolDocument object with the specified id.
        /// </summary>
        /// <param name="connectionString">Information to connect to the database</param>
        /// <param name="args">ProtocolDocument Id of the document to be loaded</param>
        public override void Load(string connectionString, params object[] args)
        {
            if (args.Length != 1)
                throw new Exception("ProtocolDocument Load expects Id");

            try
            {
                DataSet protocolDocumentDetails = Utility.DataAccess.GetDataSet(connectionString, GetProtocolDocumentByIdSProcName,
                        Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, (int)args[0]));

                DataRowCollection rows = protocolDocumentDetails.Tables[0].Rows;
                if (rows.Count > 0)
                    PopulateMembers(rows[0], false);
            }
            catch (Exception e)
            {
                Utility.ExceptionReport.WriteToEventLog("Document.Load: Failed to load the protocol document", e, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }
        }


        /// <summary>
        /// Saves the state of the ProtocolDocument object to the database. 
        /// The stored procedure inserts a new record if the id of the object is 0, 
        /// otherwise the procedure updates the record with the matching protocol document id
        /// </summary>
        /// <param name="sqlTransaction">The context in which the insert/update should be executed</param>
        protected override void SaveObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
        {
            try
            {
                object dbDateReceived = (DateReceived == DateTime.MinValue) ? (object)DBNull.Value : DateReceived;

                if (markForDeletion)
                {
                    Delete(sqlTransaction);
                }
                else
                {
                    object documentId = DBNull.Value;

                    if (!markDocumentForDeletion)
                    {
                        if (electronicFile != null)
                        {
                            if (electronicFile.IsDirty())
                            {
                                electronicFile.FolderHierarchy = CreateFolderHierarchy(this.protocolId.ToString(), electronicFile.Id, electronicFile.Name, true);
                                electronicFile.Save(sqlTransaction);
                            }

                            documentId = electronicFile.Id;
                        }
                    }

                    SqlParameter[] paramArray = DataAccess.BuildSqlParameterArray(
                        "@id", SqlDbType.Int, Id,
                        "@name", SqlDbType.VarChar, Name,
                        "@type", SqlDbType.VarChar, Type,
                        "@required", SqlDbType.Bit, Required,
                        "@hardCopy", SqlDbType.Bit, IsHardCopy,
                        "@dateReceived", SqlDbType.DateTime, dbDateReceived,
                        "@documentId", SqlDbType.Int, documentId,
                        "@protocolId", SqlDbType.Int, protocolId,
                        "@addedPPId", SqlDbType.Int, addedPPId,
                        "@removedPPId", SqlDbType.Int, removedPPId,
                        "@isCurrent", SqlDbType.Bit, isCurrent,
                        "@version", SqlDbType.Int, version,
                        "@lastLockedVersion", SqlDbType.Int, lastLockedVersion,
                        "@formsId", SqlDbType.VarChar, (formsId == null || formsId == string.Empty) ? (object)DBNull.Value : (object)formsId,
                        "@published", SqlDbType.Bit, published,
                        "@includeEditable", SqlDbType.Bit, IncludeEditable,
                        "@parentDocumentId", SqlDbType.Int, parentDocumentId
                    );

                    //set version as input output
                    paramArray[11].Direction = ParameterDirection.InputOutput;

                    Id = Convert.ToInt32(DataAccess.ExecuteScalar(sqlTransaction.Connection, sqlTransaction, SaveProtocolDocumentSProcName,
                        paramArray));

                    version = Convert.ToInt32(paramArray[11].Value);
                }

                if (markDocumentForDeletion)
                {
                    electronicFile.Delete(sqlTransaction);
                    electronicFile = null;
                    markDocumentForDeletion = false; //reset this flag as the object will be reused
                }
            }
            catch (Exception e)
            {
                Utility.ExceptionReport.WriteToEventLog("ProtocolDocument.SaveObject: Failed to save the protocol document", e, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }
        }


        /// <summary>
        /// Deletes the ProtocolDocument from the database.
        /// </summary>
        /// <param name="sqlTransaction">The transaction context in which the SQL statement is to be executed</param>
        protected override void DeleteObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
        {
            try
            {
                Utility.DataAccess.ExecuteNonQuery(sqlTransaction.Connection, sqlTransaction, DeleteProtocolDocumentSProcName,
                    Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, Id));

                if (electronicFile != null)
                    electronicFile.Delete(sqlTransaction);
            }
            catch (Exception e)
            {
                Utility.ExceptionReport.WriteToEventLog("ProtocolDocument.DeleteObject: Failed to delete the protocol document", e, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Adds an electronic file to the protocol document
        /// </summary>
        /// <param name="fileName">Name of the file</param>
        /// <param name="contents">Contents of the file</param>
        public void AddElectronicFile(string fileName, byte[] contents)
        {
            Document document = new Document(CachePolicy);
            document.Id = 0;
            document.Blob = contents;
            document.DateCreated = DateTime.Now;
            document.Name = fileName;
            ElectronicFile = document;
            DateReceived = DateTime.Now;
        }


        /// <summary>
        /// Returns all the versions for the specified protocol document. 
        /// The versions returned include the versions attached to the current process
        /// and the version that is approved and all the prior versions to the
        /// approved version
        /// </summary>
        /// <param name="connectionString">Information to connect to the database</param>
        /// <param name="cachePolicy">the prevalent cache policy</param>
        /// <returns>An arraylist of ProtocolDocument objects that represent the different versions</returns>
        public ArrayList GetDocumentVersions(string connectionString, int protocolProcessId, ICachePolicy cachePolicy)
        {

            try
            {
                ArrayList documents = new ArrayList();
                DataSet protocolDocumentVesrions = Utility.DataAccess.GetDataSet(connectionString, GetProtocolDocumentVersionsSProcName,
                    Utility.DataAccess.BuildSqlParameterArray(
                    "@id", SqlDbType.Int, Id,
                    "@name", SqlDbType.VarChar, Name,
                    "@protocolId", SqlDbType.Int, protocolId,
                    "@protocolProcessId", SqlDbType.Int, protocolProcessId));

                DataRowCollection rows = protocolDocumentVesrions.Tables[0].Rows;

                foreach (DataRow row in rows)
                {
                    documents.Add(new ProtocolDocument(cachePolicy, row, true));
                }

                return documents;

            }
            catch (Exception e)
            {
                Utility.ExceptionReport.WriteToEventLog("ProtocolDocument.GetDocumentVersions: Failed to load the protocol document versions", e, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }

        }

        #endregion

        #region Private methods
        /// <summary>
        /// Populates instance fields with corresponding values from the data row
        /// </summary>
        /// <param name="dataRow">A DataRow object holding the values to be populated to the instance fields</param>
        private void PopulateMembers(DataRow dataRow, bool gettingVersions)
        {
            Id = (int)dataRow[ColumnNameId];
            protocolId = (int)dataRow[ColumnNameProtocolId];
            name = (string)dataRow[ColumnNameName];
            addedPPId = (int)dataRow[ColumnNameAddedPPId];
            type = (string)dataRow[ColumnNameType];
            if (dataRow.Table.Columns.Contains(ColumnNameRefMeaning))
                refMeaning = (string)dataRow[ColumnNameRefMeaning];

            required = (bool)dataRow[ColumnNameRequired];
            hardCopy = (bool)dataRow[ColumnNameHardCopy];
            object o = dataRow[ColumnNameDateReceived];
            dateReceived = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;
            removedPPId = (int)dataRow[ColumnNameRemovedPPId];
            isCurrent = (bool)dataRow[ColumnNameIsCurrent];
            version = (int)dataRow[ColumnNameVersion];
            parentDocumentId = (int)dataRow[ColumnNameParentId];
            if (dataRow[ColumnNameDocumentId] != DBNull.Value)
            {
                electronicFile = new Document(CachePolicy);
                electronicFile.Id = (int)dataRow[ColumnNameDocumentId];
                if (dataRow[ColumnNameFileName] != DBNull.Value)
                {
                    electronicFile.Name = (string)dataRow[ColumnNameFileName];
                }
                if (dataRow.Table.Columns.Contains("IsConvertedToPdf") && dataRow["IsConvertedToPdf"] != DBNull.Value)
                {
                    electronicFile.IsConvertedToPdf = Convert.ToBoolean(dataRow["IsConvertedToPdf"]);
                }
            }
            if (dataRow.Table.Columns.Contains(ColumnNameReplaceable))
                replaceable = (bool)dataRow[ColumnNameReplaceable];
            if (dataRow.Table.Columns.Contains("ProcessName"))
            {
                o = dataRow["ProcessName"];
                processName = (o == DBNull.Value) ? string.Empty : (string)o;
            }
            if (dataRow.Table.Columns.Contains("ProcessType"))
            {
                o = dataRow["ProcessType"];
                processType = (o == DBNull.Value) ? string.Empty : (string)o;
            }
            if (dataRow.Table.Columns.Contains("FormsId"))
            {
                o = dataRow["FormsId"];
                formsId = (o == DBNull.Value) ? string.Empty : (string)o;
            }
            if (dataRow.Table.Columns.Contains("Published"))
            {
                o = dataRow["Published"];
                published = (o == DBNull.Value) ? false : (bool)o;
            }
        }

        #endregion

        #region Static methods for loading
        /// <summary>
        /// Loads all ProtocolDocuments for a given Process for approval
        /// </summary>
        /// <param name="protocolId">The ID of the Protocol</param>
        /// <param name="protocolProcessId">Procotolprocess Id</param>
        /// <param name="cachePolicy">The prevalent cache policy</param>
        /// <returns>Returns an arraylist of ProtocolDocuments, if none exist, the array list count is zero.</returns>
        public static ArrayList GetProtocolDocumentsForApproval(int protocolId, int protocolProcessId, ICachePolicy cachePolicy)
        {
            return GetProtocolDocuments(cachePolicy, protocolId, protocolProcessId, true);
        }

        /// <summary>
        /// Loads all ProtocolDocuments for a given Protocol
        /// </summary>
        /// <param name="protocolId">The ID of the Protocol</param>
        /// <param name="cachePolicy">The prevalent cache policy</param>
        /// <returns>Returns an arraylist of ProtocolDocuments, if none exist, the array list count is zero.</returns>
        public static ArrayList GetProtocolDocuments(int protocolId, ICachePolicy cachePolicy)
        {
            return GetProtocolDocuments(protocolId, 0, cachePolicy);
        }


        /// <summary>
        /// Loads all ProtocolDocuments for a given ProtocolProcess.
        /// </summary>
        /// <param name="protocolId">The ID of the Protocol</param>
        /// <param name="protocolProcessId">Id of the process</param>
        /// <param name="cachePolicy">The prevalent cache policy</param>
        /// <returns>Returns an arraylist of ProtocolDocuments, if none exist, the array list count is zero.</returns>
        public static ArrayList GetProtocolDocuments(int protocolId, int protocolProcessId, ICachePolicy cachePolicy)
        {
            return GetProtocolDocuments(cachePolicy, protocolId, protocolProcessId, false);
        }


        private static ArrayList GetProtocolDocuments(ICachePolicy cachePolicy, int protocolId, int protocolProcessId, bool forApproval)
        {
            ArrayList documents = new ArrayList();
            try
            {
                DataSet documentsDataSet = Utility.DataAccess.GetDataSet(Utility.DataAccess.ConnectionString, GetProtocolDocumentsSProcName,
                    Utility.DataAccess.BuildSqlParameterArray
                    (
                    "@protocolId", SqlDbType.Int, protocolId,
                    "@protocolProcessId", SqlDbType.Int, protocolProcessId
                    ));

                DataRowCollection rows = documentsDataSet.Tables[0].Rows;

                foreach (DataRow row in rows)
                {
                    //if not for approval, then do not include the rows which are removed
                    int removedPPId = (int)row[ColumnNameRemovedPPId];
                    if (!forApproval && (protocolProcessId != 0 && removedPPId == protocolProcessId))
                        continue;
                    documents.Add(new ProtocolDocument(cachePolicy, row, false));
                }
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("ProtocolDocument.GetProtocolDocuments: Failed to load protocol documents for the specified process", ex, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }
            return documents;
        }


        /// <summary>
        /// Gets all the protocol document names that are associated with the protocol.
        /// </summary>
        /// <param name="cachePolicy">The prevalent cache policy</param>
        /// <param name="protocolId">Id of the protocol</param>
        /// <returns>Name & type seperated by '@' of the protocol documents delimited by a '|' and enclosed within '|'</returns>
        public static string GetProtocolDocumentNames(ICachePolicy cachePolicy, int protocolId)
        {
            string names = string.Empty;
            try
            {
                names = Convert.ToString(Utility.DataAccess.ExecuteScalar(Utility.DataAccess.ConnectionString, "GetProtocolDocumentNames",
                    Utility.DataAccess.BuildSqlParameterArray
                    (
                    "@protocolId", SqlDbType.Int, protocolId
                    )));
            }
            catch (Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("ProtocolDocument.GetProtocolDocumentNames: Failed to get the names of protocol documents for the protocol", ex, true, Utility.ExceptionReport.ReportType.Error);
                throw;
            }
            return names;
        }

        /// <summary>
        /// Gets a unique title for the specified document type
        /// </summary>
        /// <param name="cachePolicy">Prevalent cache policy</param>
        /// <param name="protocolId">Protocol Id</param>
        /// <param name="attachmentTypeMeaning">Type Meaning of the attachment for which a unique title has to be generated</param>
        /// <param name="attachmentType">Type of the attachment for which a unique title has to be generated</param>
        /// <returns>Unique title</returns>
        public static string GetNewTitleForType(ICachePolicy cachePolicy, int protocolId, string attachmentTypeMeaning, string attachmentType)
        {

            string documentNames = GetProtocolDocumentNames(cachePolicy, protocolId);

            int suffix = 1;
            string newTitle;
            do
            {
                newTitle = string.Format("{0} {1}", attachmentTypeMeaning, suffix.ToString("000"));
                ++suffix;
            }
            while (documentNames.IndexOf(string.Format("|{0}@{1}|", newTitle, attachmentType)) != -1);
            return newTitle;
        }
        /// <summary>
        /// Create the url for sharepoint
        /// </summary>
        /// <param name="protocolId"></param>
        /// <param name="docId"></param>
        /// <returns></returns>
        public static string CreateFolderHierarchy(Protocol protocol, int docId, string fileName)
        {

            string folderHierarchy = string.Empty;

            string documentId = (docId == 0 ? Constants.IdPrefix : docId.ToString());
            string filExtension = fileName.Substring(fileName.LastIndexOf('.'), fileName.Length - (fileName.LastIndexOf('.')));
            string moduleName = protocol.ModuleType == "H" ? "Humans" : "Animals";
            string url = Utility.Settings.GetKeyValue("SharePointBlobURL", string.Empty);
            string docLibName = Utility.Settings.GetKeyValue("DocLibName", "Document");

            if (string.IsNullOrEmpty(protocol.ProtocolNumber))
            {
                url += "/" + moduleName + "/" + DateTime.Now.Year + "/" + docLibName;
            }
            else
            {

                url += "/" + moduleName + "/" + protocol.ProtocolNumber.ToString().Substring(0, 4) + "/" + docLibName;
            }
            folderHierarchy = url + "/" + protocol.Id + "/" + documentId + filExtension;

            return folderHierarchy;
        }


        /// <summary>
        /// Create the url For Animal Clone
        /// </summary>
        /// <param name="protocolId"></param>
        /// <param name="docId"></param>
        /// <returns></returns>
        public static string CreateFolderHierarchy(string protocolId, int docId, string fileName, bool isClonedDocument)
        {

            string folderHierarchy = string.Empty;
            string documentId = (docId == 0 ? Constants.IdPrefix : docId.ToString());
            string filExtension = fileName.Substring(fileName.LastIndexOf('.'), fileName.Length - (fileName.LastIndexOf('.')));
            string url = Utility.Settings.GetKeyValue("SharePointBlobURL", string.Empty);
            string docLibName = Utility.Settings.GetKeyValue("DocLibName", "Document");
            if (isClonedDocument)
            {
                url += "/" + "Animals" + "/" + DateTime.Now.Year + "/" + docLibName;

            }
            else
            {
                Policy.ICachePolicy cachePolicy = new Policy.NullCachePolicy();
                Protocol protocol = new Protocol(cachePolicy);
                protocol.Load(Utility.DataAccess.ConnectionString, protocolId);
                string moduleName = protocol.ModuleType == "H" ? "Humans" : "Animals";
                if (string.IsNullOrEmpty(protocol.ProtocolNumber))
                {
                    url += "/" + moduleName + "/" + DateTime.Now.Year + "/" + docLibName;
                }
                else
                {

                    url += "/" + moduleName + "/" + protocol.ProtocolNumber.ToString().Substring(0, 4) + "/" + docLibName;
                }
            }
            folderHierarchy = url + "/" + protocolId + "/" + documentId + filExtension;

            return folderHierarchy;


        }


        #endregion

        /// <summary>
        /// Check if the new protocol document match business requirements, which currently include 
        /// 1. for Protocol Summary and detailed protocol, attachments need to be versioned, 
        ///     and the title can only be 'protocol summary' or 'detailed protocol' 
        /// 2. if a type and title exist in database, the new document need to have a different title. 
        /// 3. for consent forms, prompt user to use versions
        /// </summary>
        /// <param name="protocolId">Protocol Id</param>
        /// <param name="attachmentType">type of the newly attached document</param>
        /// <param name="attachmentTitle">title of the newly attched document</param>
        /// /// <param name="resave">if the document is beign checked during resave</param>
        /// <returns>return attachment validation code by checking data in database, 
        /// if returned enum value VALID, no error; 
        /// if returned enum VersionReq, error: protocol summary/detailed protocol type exist, new attachment need to be added to versions; 
        /// if returned enum VersionSug, warning: consent form type exists, new one is suggested to use version; 
        /// if returned enum Duplicated, error: same type, title document exists in database, use a different title
        /// </returns>
        public static AttachmentValidationStatus ValidateAttachment(int protocolId, string attachmentType, string attachmentTitle, bool resave)
        {
            DataTable attachmentValidationResult = DataAccess.GetDataTable(
                    Utility.DataAccess.ConnectionString, ValidateProtocolDocumentsProcName,
                        Utility.DataAccess.BuildSqlParameterArray
                        (
                        "@protocolId", SqlDbType.Int, protocolId,
                        "@attachType", SqlDbType.VarChar, attachmentType,
                        "@attachTitle", SqlDbType.VarChar, attachmentTitle, 
                        "@Resave", SqlDbType.Bit,resave
                        )
                    );
            AttachmentValidationStatus attaStatus = new AttachmentValidationStatus();
            attaStatus.ValidationCode = (string)attachmentValidationResult.Rows[0][0];
            attaStatus.ValidationMsg = (string)attachmentValidationResult.Rows[0][1];
            return attaStatus;
        }
    }
    #endregion

    public class AttachmentValidationStatus
    {
        private string validationCode;
        private string validationMsg;
        /// <summary>
        /// returned code after DB checking of newly attached protocol document
        /// </summary>
        public string ValidationCode
        {
            get
            {
                return validationCode;
            }
            set
            {
                validationCode = value;
            }
        }

        /// <summary>
        /// returned code after DB checking of newly attached protocol document
        /// </summary>
        public string ValidationMsg
        {
            get
            {
                return validationMsg;
            }
            set
            {
                validationMsg = value;
            }
        }
    }
}
